using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class OperatorProductionSpecification {
        private void AssertParseOperator (string sourceString) {
            ParseResult result = ParseOperator (sourceString);

            Assert.IsNotNull (result);
            Assert.AreEqual (sourceString.Length, result.Index);
            Assert.IsTrue (result.Term is IdentifierTerm);
            Assert.AreEqual (sourceString, ((IdentifierTerm) result.Term).Name);
        }

        private void AssertPartiallyParseOperator (string expectedOperator, string sourceString) {
            ParseResult result = ParseOperator (sourceString);

            Assert.IsNotNull (result);
            Assert.AreEqual (expectedOperator.Length, result.Index);
            Assert.IsTrue (result.Term is IdentifierTerm);
            var identifier = (IdentifierTerm) result.Term;
            Assert.AreEqual (expectedOperator, identifier.Name);
            Assert.AreEqual (0, identifier.SourceInformation.Index);
            Assert.AreEqual (expectedOperator.Length, identifier.SourceInformation.Length);
        }

        private void AssertNotParseOperator (string sourceString) {
            ParseResult result = ParseOperator (sourceString);

            Assert.IsNull (result);
        }

        private ParseResult ParseOperator (string sourceString) {
            var id = OperatorProduction.CreateTerminal ();

            var source = sourceString;

            return id.Parse (source, 0, new ParseContext ());
        }

        [Test]
        public void ShouldParseValidIdentifiers () {
            AssertParseOperator ("!@#");
            AssertParseOperator ("*#&");
            AssertParseOperator ("+");
            AssertParseOperator ("+=");
            AssertParseOperator ("=/*-+");
            AssertParseOperator ("=/*:+");
        }

        [Test]
        public void ShouldFailOnInvalidIdentifiers () {
            AssertNotParseOperator ("abc");
            AssertNotParseOperator ("a-b-c");
            AssertNotParseOperator ("");
        }

        [Test]
        public void ShouldPartiallyParseIdentifiers () {
            AssertPartiallyParseOperator ("@#$", "@#${");
            AssertPartiallyParseOperator ("@#$", "@#$abc");
            AssertPartiallyParseOperator ("@#$", "@#$ ");
            AssertPartiallyParseOperator ("@#$", "@#$\n");
        }
    }
}